home *** CD-ROM | disk | FTP | other *** search
- /*
- * Center for Information Technology Integration
- * The University of Michigan
- * Ann Arbor
- *
- * Dedicated to the public domain.
- * Send questions to info@citi.umich.edu
- *
- * BOOTP is documented in RFC 951 and RFC 1048
- * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
- */
-
-
- #include "global.h"
- #ifdef BOOTPCLIENT
- #include "commands.h"
- #ifndef MSDOS
- #include <time.h>
- #endif
- #include "mbuf.h"
- #include "netuser.h"
- #include "udp.h"
- #include "domain.h"
- #include "bootp.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: bootp.c,v 1.17 1997/01/19 21:13:05 root Exp root $";
- #endif
-
- static int bootp_rx (struct iface *ifp, struct mbuf *bp);
- static void ntoh_bootp (struct mbuf **bpp, struct bootp *bootpp);
-
- #if 0
- static int mask2width (int32 mask);
- #endif
-
- #define BOOTP_TIMEOUT 30 /* Time limit for booting */
- #define BOOTP_RETRANS 5 /* The inteval between sendings */
-
- #ifdef BOOTP
- int WantBootp = 0;
- #endif
-
- static int SilentStartup = 0;
-
-
-
- int
- dobootp (int argc, char **argv, void *p OPTIONAL)
- {
- struct iface *ifp = NULLIF;
- struct socket lsock, fsock;
- struct mbuf *bp;
- struct udp_cb *bootp_cb;
- register unsigned char *cp;
- time_t now, /* The current time (seconds) */
- starttime, /* The start time of sending BOOTP */
- lastsendtime; /* The last time of sending BOOTP */
- int i;
-
- if (argc < 2) /* default to the first interface */
- ifp = Ifaces;
- else {
- for (i = 1; i != argc; ++i) {
-
- if ((ifp = if_lookup (argv[i])) != NULLIF)
- continue;
- else if (strncmp (argv[i], "silent", strlen (argv[i])) == 0)
- SilentStartup = 1;
- else if (strncmp (argv[i], "noisy", strlen (argv[i])) == 0)
- SilentStartup = 0;
- else {
- tputs ("bootp [net_name] [silent] [noisy]\n");
- return 1;
- }
- }
- }
-
- if (ifp == NULLIF)
- return 0;
-
- lsock.address = ifp->addr;
- lsock.port = IPPORT_BOOTPC;
-
- if ((bootp_cb = open_udp (&lsock, NULLVFP ((struct iface *, struct udp_cb *, int16)))) == NULLUDP)
- return 0;
-
- fsock.address = ifp->broadcast;
- fsock.port = IPPORT_BOOTPS;
-
- /* Get boot starting time */
- (void) time (&starttime);
- lastsendtime = 0;
-
- /* Send the bootp request packet until a response is received or time
- out */
- for ( ; ; ) {
-
- /* Allow bootp packets should be passed through iproute. */
- WantBootp = 1;
-
- /* Get the current time */
- (void) time (&now);
-
- /* Stop, if time out */
- if (now - starttime >= BOOTP_TIMEOUT) {
- tputs ("bootp: timed out, values not set\n");
- break;
- }
- /* Don't flood the network, send in intervals */
- if (now - lastsendtime > BOOTP_RETRANS) {
- if (!SilentStartup)
- tputs ("Requesting...\n");
-
- /* Allocate BOOTP packet and fill it in */
- if ((bp = alloc_mbuf (sizeof (struct bootp))) == NULLBUF)
- break;
-
- cp = bp->data; /* names per the RFC: */
- *cp++ = BOOTREQUEST; /* op */
- *cp++ = uchar(ifp->iftype->type); /* htype */
- *cp++ = uchar(ifp->iftype->hwalen); /* hlen */
- *cp++ = 0; /* hops */
- cp = put32 (cp, (uint32) now); /* xid */
- cp = put16 (cp, (int16)(now - starttime)); /* secs */
- cp = put16 (cp, 0); /* unused */
- cp = put32 (cp, ifp->addr); /* ciaddr */
- cp = put32 (cp, 0L); /* yiaddr */
- cp = put32 (cp, 0L); /* siaddr */
- cp = put32 (cp, 0L); /* giaddr */
- memcpy (cp, ifp->hwaddr, (size_t) ifp->iftype->hwalen);
- cp += 16; /* chaddr */
- memset (cp, 0, 64); /* sname */
- cp += 64;
- memset (cp, 0, 128); /* file */
- cp += 128;
- memset (cp, 0, 64); /* vend */
- cp += 64;
- bp->cnt = (int16)(cp - bp->data);
- /* assert(bp->cnt == BOOTP_LEN) */
-
- /* Send out one BOOTP Request packet as a broadcast */
- (void) send_udp (&lsock, &fsock, 0, 0, bp, bp->cnt, 0, 0);
-
- lastsendtime = now;
- }
- /* Give other tasks a chance to run. */
- kwait (NULL);
-
- /* Test for and process any replies */
- if (recv_udp (bootp_cb, &fsock, &bp) > -1) {
- if (bootp_rx (ifp, bp))
- break;
- } else if (Net_error != WOULDBLK) {
- tprintf ("bootp: Net_error %d, no values set\n", Net_error);
- break;
- }
- }
-
- WantBootp = 0;
- (void) del_udp (bootp_cb);
- return 0;
- }
-
-
-
- /* Process BOOTP input received from 'interface'. */
- static int
- bootp_rx (struct iface *ifp, struct mbuf *bp)
- {
- int ch;
- int count;
- uint32 gateway = 0;
- uint32 nameserver = 0;
- uint32 broadcast, netmask;
- struct route *rp;
- struct bootp reply;
- unsigned char *cp;
-
- if (len_p (bp) != sizeof (struct bootp)) {
- free_p (bp);
- return 0;
- }
- ntoh_bootp (&bp, &reply);
- free_p (bp);
-
- if (reply.op != BOOTREPLY)
- return 0;
-
- if (!SilentStartup)
- tprintf ("Network %s configured:\n", ifp->name);
-
- if (ifp->addr == 0) {
- Ip_addr = reply.yiaddr.s_addr; /* yiaddr */
- ifp->addr = reply.yiaddr.s_addr; /* yiaddr */
- if (!SilentStartup)
- tprintf (" IP address: %s\n", inet_ntoa (ifp->addr));
- }
- /* now process the vendor-specific block, check for cookie first. */
- cp = (unsigned char *) reply.vend;
- if (get32 (reply.vend) != 0x63825363L) {
- tcmdprintf ("bootp: Invalid magic cookie.\n");
- return (0);
- }
- cp += 4;
- while (((ch = *cp) != BOOTP_END) && (++cp < (unsigned char *) (reply.vend + 64)))
- switch (ch) {
- case BOOTP_PAD: /* They're just padding */
- continue;
- case BOOTP_SUBNET: /* fixed length, 4 octets */
- cp++; /* moved past length */
-
- /* Set the netmask */
- /* Remove old entry if it exists */
- netmask = get32 ((char *) cp);
- cp += 4; /*lint !e662 */
-
- rp = rt_blookup (ifp->addr & ifp->netmask, (unsigned) mask2width (ifp->netmask));
- if (rp != NULLROUTE)
- (void) rt_drop (rp->target, rp->bits);
- ifp->netmask = netmask;
- (void) rt_add (ifp->addr, (unsigned) mask2width (ifp->netmask), 0L, ifp, 0L, 0L, 0);
-
- if (!SilentStartup)
- tprintf (" Subnet mask: %s\n", inet_ntoa (netmask));
-
- /* Set the broadcast */
- broadcast = ifp->addr | ~(ifp->netmask);
- rp = rt_blookup (ifp->broadcast, 32);
- if (rp != NULLROUTE && rp->iface == ifp)
- (void) rt_drop (ifp->broadcast, 32);
- ifp->broadcast = broadcast;
- (void) rt_add (ifp->broadcast, 32, 0L, ifp, 1L, 0L, 1);
-
- if (!SilentStartup)
- tprintf (" Broadcast: %s\n", inet_ntoa (broadcast));
-
- break;
- case BOOTP_HOSTNAME:
- count = (int) *cp;
- cp++;
-
- if (Hostname != NULLCHAR)
- free (Hostname);
- Hostname = mallocw ((unsigned) count);
- strncpy (Hostname, (char *) cp, (size_t) count);
- cp += count;
-
- if (!SilentStartup)
- tprintf (" Hostname: %s\n", Hostname);
- break;
- case BOOTP_DNS:
- count = (int) *cp;
- cp++;
-
- while (count) {
- nameserver = get32 ((char *) cp);
- (void) add_nameserver (nameserver, 0);
- if (!SilentStartup)
- tprintf (" Nameserver: %s\n", inet_ntoa (nameserver));
- cp += 4; /*lint !e662 */
- count -= 4;
- }
- break;
- case BOOTP_GATEWAY:
- count = (int) *cp;
- cp++;
-
- gateway = get32 ((char *) cp);
-
- /* Add the gateway as the default */
- (void) rt_add (0, 0, gateway, ifp, 1, 0, 0);
-
- if (!SilentStartup)
- tprintf (" Default gateway: %s\n", inet_ntoa (gateway));
- cp += count;
- break;
- default: /* variable field we don't know about */
- count = (int) *cp;
- cp++;
-
- cp += count;
- break;
- }
-
- (void) rt_add (ifp->addr, (unsigned) mask2width (ifp->netmask), 0L, ifp, 1, 0, 0); /*lint !e661 !e662 */
-
- return (1);
- }
-
-
-
- static void
- ntoh_bootp (struct mbuf **bpp, struct bootp *bootpp)
- {
- bootpp->op = (char) pullchar (bpp); /* op */
- bootpp->htype = (char) pullchar (bpp); /* htype */
- bootpp->hlen = (char) pullchar (bpp); /* hlen */
- bootpp->hops = (char) pullchar (bpp); /* hops */
- bootpp->xid = (long) pull32 (bpp); /* xid */
- bootpp->secs = pull16 (bpp); /* secs */
- bootpp->unused = pull16 (bpp); /* unused */
- bootpp->ciaddr.s_addr = pull32 (bpp); /* ciaddr */
- bootpp->yiaddr.s_addr = pull32 (bpp); /* ciaddr */
- bootpp->siaddr.s_addr = pull32 (bpp); /* siaddr */
- bootpp->giaddr.s_addr = pull32 (bpp); /* giaddr */
- (void) pullup (bpp, (unsigned char *) bootpp->chaddr, 16); /* chaddr */
- (void) pullup (bpp, (unsigned char *) bootpp->sname, 64); /* sname */
- (void) pullup (bpp, (unsigned char *) bootpp->file, 128); /* file name */
- (void) pullup (bpp, (unsigned char *) bootpp->vend, 64); /* vendor */
- }
-
-
-
- #ifdef BOOTP
-
- int
- bootp_validPacket (struct ip *ip, struct mbuf **bpp)
- {
- struct udp udp;
- struct pseudo_header ph;
- int status;
-
-
- /* Must be a udp packet */
- if (ip->protocol != UDP_PTCL)
- return 0;
-
- /* Invalid if packet is not the right size */
- if (len_p (*bpp) != (sizeof (struct udp) + sizeof (struct bootp)))
- return 0;
-
- /* Invalid if not a udp bootp packet */
- ntohudp (&udp, bpp);
-
- status = (udp.dest == IPPORT_BOOTPC) ? 1 : 0;
-
- /* Restore packet, data hasn't changed */
- /* Create pseudo-header and verify checksum */
- ph.source = ip->source;
- ph.dest = ip->dest;
- ph.protocol = ip->protocol;
- ph.length = ip->length - IPLEN - ip->optlen;
-
- *bpp = htonudp (&udp, *bpp, &ph);
-
- return status;
- }
-
- #endif
-
-
-
- #if 0 /* no longer needed, as it is in iface.c */
- /* Given a network mask, return the number of contiguous 1-bits starting
- * from the most significant bit.
- */
- static int
- mask2width (int32 mask)
- {
- int width, i;
-
- width = 0;
- for (i = 31; i >= 0; i--) {
- if (!(mask & (1L << i)))
- break;
- width++;
- }
- return width;
- }
-
- #endif
-
- #endif /* BOOTPCLIENT */
-